package com.cloudweb.oa.controller;

import cn.hutool.core.codec.Base64;
import cn.js.fan.cache.jcs.RMCache;
import cn.js.fan.security.ThreeDesUtil;
import cn.js.fan.util.ErrMsgException;
import cn.js.fan.util.ParamUtil;
import cn.js.fan.util.RandomSecquenceCreator;
import cn.js.fan.util.StrUtil;
import cn.js.fan.web.Global;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baidu.ueditor.ActionEnter;
import com.cloudweb.oa.api.IMsgProducer;
import com.cloudweb.oa.config.JwtProperties;
import com.cloudweb.oa.entity.User;
import com.cloudweb.oa.exception.InvalidTokenVerException;
import com.cloudweb.oa.exception.ValidateException;
import com.cloudweb.oa.security.AuthUtil;
import com.cloudweb.oa.security.LoginUtil;
import com.cloudweb.oa.service.IFileService;
import com.cloudweb.oa.service.IUserService;
import com.cloudweb.oa.service.MacroService;
import com.cloudweb.oa.service.SsoService;
import com.cloudweb.oa.utils.*;
import com.cloudweb.oa.vo.Result;
import com.cloudwebsoft.framework.security.AesUtil;
import com.cloudwebsoft.framework.util.LogUtil;
import com.redmoon.dingding.Config;
import com.redmoon.dingding.service.user.UserService;
import com.redmoon.oa.base.IAttachment;
import com.redmoon.oa.flow.*;
import com.redmoon.oa.flow.macroctl.MacroCtlMgr;
import com.redmoon.oa.flow.macroctl.MacroCtlUnit;
import com.redmoon.oa.message.MessageDb;
import com.redmoon.oa.person.UserDb;
import com.redmoon.oa.pvg.Privilege;
import com.redmoon.oa.security.SecurityUtil;
import com.redmoon.oa.sms.IMsgUtil;
import com.redmoon.oa.sms.SMSFactory;
import com.redmoon.oa.stamp.StampDb;
import com.redmoon.oa.stamp.StampPriv;
import com.redmoon.oa.visual.ModuleSetupDb;
import com.redmoon.oa.visual.SQLBuilder;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.Length;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import java.awt.*;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Vector;

import com.redmoon.oa.util.MobileScanDownload;
import nl.bitwalker.useragentutils.OperatingSystem;
import nl.bitwalker.useragentutils.UserAgent;

@Slf4j
@Controller
@RequestMapping("/public")
public class PublicController {

    @Autowired
    HttpServletRequest request;

    @Autowired
    SysUtil sysUtil;

    @Autowired
    LoginUtil loginUtil;

    @Autowired
    AuthUtil authUtil;

    @Autowired
    JwtUtil jwtUtil;

    @Autowired
    JwtProperties jwtProperties;

    @Autowired
    SysProperties sysProperties;

    @Autowired
    MacroService macroService;

    @Autowired
    SsoService ssoService;

    @Autowired
    IUserService userService;

    @Autowired
    private IFileService fileService;

    @ApiOperation(value = "取得服务端信息", notes = "取得服务端信息", httpMethod = "GET")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @RequestMapping(value = "/getServerInfo", produces = {"text/html;charset=UTF-8;", "application/json;"})
    @ResponseBody
    public Result<Object> getServerInfo() {
        JSONObject json = sysUtil.getServerInfo();
        com.redmoon.oa.Config cfg = com.redmoon.oa.Config.getInstance();
        json.put("isMenuGroupByApplication", cfg.getBooleanProperty("isMenuGroupByApplication"));
        json.put("isWxLoginEnabled", cfg.getBooleanProperty("isWxLoginEnabled"));
        json.put("isMobileLoginEnabled", cfg.getBoolean("isMobileLoginEnabled"));

        com.redmoon.oa.security.Config myconfig = com.redmoon.oa.security.Config.getInstance();
        json.put("isPwdCanReset", myconfig.getIntProperty("isPwdCanReset"));
        String pwdName = myconfig.getProperty("pwdName");
        String pwdAesKey = myconfig.getProperty("pwdAesKey");
        String pwdAesIV = myconfig.getProperty("pwdAesIV");
        json.put("pwdName", pwdName);
        json.put("pak", Base64.encode(pwdAesKey));
        json.put("pai", Base64.encode(pwdAesIV));
        int loginMode = com.redmoon.oa.Config.getInstance().getInt("loginMode");
        json.put("loginMode", loginMode);
        json.put("id", sysProperties.getId());
        json.put("showId", sysProperties.isShowId());
        json.put("isUserEmailRequired", sysProperties.isUserEmailRequired());
        json.put("isUserMobileRequired", sysProperties.isUserMobileRequired());

        String systemLoginParam = "";
        try {
            systemLoginParam = AesUtil.aesEncrypt(cfg.get("systemLoginParam"), pwdAesKey, pwdAesIV);
        } catch (Exception e) {
            LogUtil.getLog(getClass()).error(e);
        }
        json.put("systemIsOpen", cfg.getBooleanProperty("systemIsOpen"));
        json.put("systemLoginParam", systemLoginParam);
        json.put("systemStatus", cfg.get("systemStatus"));
        json.put("rootPath", sysUtil.getRootPath());
        // 手机端是否启用
        json.put("isUseClient", cfg.getBoolean("isUseClient"));
        json.put("wxAppId", sysProperties.getWxAppId());
        json.put("frontPath", sysUtil.getFrontPath());
        return new Result<>(json);
    }

    // ueditor.all.js:8284 跨源读取阻止(CORB)功能阻止了 MIME 类型为 http://localhost:8085/oa/public/config?action=config&callback=bd__editor__u9fmg1 的跨源响应 text/html
    // 通过 script 标签, 本应获取到javascript内容，结果获取到 html 的内容(如果此时指定了 nosniff, 浏览器会直接认为响应内容是 text/html). 从而会触发 CORB, 响应会被清空;

    @ApiOperation(value = "配置ueditor后端上传接口的初始化，注意一定要返回text/javascript，否则浏览器会报corb错误, 响应会被清空", notes = "配置ueditor后端上传接口的初始化，注意一定要返回text/javascript，否则浏览器会报corb错误, 响应会被清空", httpMethod = "GET")
    @RequestMapping(value = "/config", produces = {"text/javascript;charset=UTF-8;"})
    @ResponseBody
    public String config(HttpServletRequest request, String action) {
        log.info("UEditor action: " + action);
        if ("config".equals(action)) {
            try {
                request.setCharacterEncoding("utf-8");
            } catch (UnsupportedEncodingException e) {
                LogUtil.getLog(getClass()).error(e);
            }
            // response.setHeader("Content-Type", "text/html");
            /*String path = getClass().getResource("/config.json").getFile();
            path = URLDecoder.decode(path, "utf-8");*/

            // String rootPath = request.getSession().getServletContext().getRealPath("/");

            // 返回：bd__editor__hrcbcw({"state": "\u914d\u7f6e\u6587\u4ef6\u521d\u59cb\u5316\u5931\u8d25"});

            // 此处用Global.getRealPath()其实是随便写的，因为在自定义的com.baidu.ueditor.ConfigManager.java中已经重写了读文件的方法
            return new ActionEnter(request, Global.getRealPath()).exec();

            // String path = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "config";

            /*PrintWriter printWriter = null;
            try {
                printWriter = response.getWriter();
            } catch (IOException e) {
                LogUtil.getLog(getClass()).error(e);
            }
            printWriter.write(new ActionEnter(request, path).exec());
            printWriter.flush();
            printWriter.close();*/
        }
        return null;
    }

    @ApiOperation(value = "H5应用通过code登录钉钉", notes = "H5应用通过code登录钉钉，取得用户信息", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "钉钉端返回的code", dataType = "String"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @ResponseBody
    @RequestMapping(value = "/loginByCodeForDingDing", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> loginByCodeForDingDing(String code, HttpServletResponse response) {
        JSONObject jsonObject = new JSONObject();
        Config cfg = Config.getInstance();
        if (!cfg.isUseDingDing()) {
            return new Result<>(false, "请在后台启用钉钉");
        }

        UserService userService = new UserService();
        UserDb userDb = userService.getUserByAvoidLogin(code);
        if (userDb != null && userDb.isLoaded()) {
            String dingding = StrUtil.getNullStr(userDb.getDingding());
            // 保存code
            if ("".equals(dingding)) {
                userDb.setDingding(code);
                userDb.save();
            }

            // 使用jwt将姓名写入token中
            String authToken = jwtUtil.generate(userDb.getName());
            jsonObject.put("token", authToken);
            JSONObject serverInfo = loginUtil.generateServerInfo(userDb.getName());
            jsonObject.put("serverInfo", serverInfo);
            response.setHeader(jwtProperties.getHeader(), authToken);
            return new Result<>(jsonObject);
        } else {
            return new Result<>(false, "code 对应的用户不存在");
        }
    }

    @ApiOperation(value = "跳转", notes = "跳转", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "op", value = "操作", dataType = "String"),
            @ApiImplicitParam(name = "action", value = "动作", dataType = "String"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @RequestMapping(value = "/jump", produces = {MediaType.APPLICATION_JSON_VALUE})
    @ResponseBody
    public Result<Object> jump(HttpServletResponse response, @RequestParam String op, @RequestParam String action) {
        // 单点登录
        if (op.equals(ConstUtil.OP_SSO)) {
            JSONObject jsonObject = new JSONObject();
            /*if ("f4c0df1b2f58483ab".equals(action)) {
                User user = userService.getUserByLoginName("test");
                // 使用jwt将姓名写入token中
                String authToken = jwtUtil.generate(user.getName());
                jsonObject.put("token", authToken);
                JSONObject serverInfo = loginUtil.generateServerInfo(user.getName());
                jsonObject.put("serverInfo", serverInfo);

                response.setHeader(jwtProperties.getHeader(), authToken);
                return new Result<>(jsonObject);
            }*/
            String authToken = ssoService.syncOrg(action);
            jsonObject.put("token", authToken);
            response.setHeader(jwtProperties.getHeader(), authToken);
            return new Result<>(jsonObject);
        } else if (op.equals(ConstUtil.OP_SSO_WITH_TOKEN)) {
            if (StringUtils.hasText(action)) {
                try {
                    // 获取 Authentication
                    if (StringUtils.hasText(action) && action.startsWith(jwtProperties.getStartWith())) {
                        action = action.substring(jwtProperties.getStartWith().length());
                    }

                    UsernamePasswordAuthenticationToken authentication = jwtUtil.getAuthentication(action);

                    String userName = (String) authentication.getPrincipal();
                    authUtil.doLoginByUserName(request, userName);

                    // 生成token
                    String authToken = jwtUtil.generate(userName);
                    response.setHeader(jwtProperties.getHeader(), authToken);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("token", authToken);

                    JSONObject serverInfo = loginUtil.generateServerInfo(userName);
                    jsonObject.put("serverInfo", serverInfo);
                    return new Result<>(jsonObject);
                } catch (InvalidTokenVerException e) {
                    return new Result<>(false, e.getMessage());
                }
            } else {
                return new Result<>(false, "用户未登录，原因可能是token非法");
            }
        }

        com.redmoon.oa.sso.Config ssoCfg = new com.redmoon.oa.sso.Config();
        action = ThreeDesUtil.decrypthexstr(ssoCfg.getKey(), action);
        LogUtil.getLog(getClass()).info("action=" + action + " op=" + op);
        String[] ary = StrUtil.split(action, "\\|");
        if (ary == null) {
            return new Result<>(false, "操作非法！");
        }
        Map<String, String> map = new HashMap<>();
        for (String s : ary) {
            String[] pair = s.split("=");
            if (pair.length == 2) {
                map.put(pair[0], pair[1]);
            }
        }

        String userName = StrUtil.getNullStr(map.get("userName"));
        LogUtil.getLog(getClass()).info("userName=" + userName);

        UserDb user = new UserDb();
        if (op.equals(ConstUtil.OP_RESET_PWD)) {
            user = user.getUserDbByLoginName(userName);
        } else {
            user = user.getUserDb(userName);
        }

        if (!user.isLoaded()) {
            return new Result<>(false, "用户不存在！");
        }

        if (!user.isValid()) {
            return new Result<>(false, "用户非法！");
        }

        authUtil.doLoginByUserName(request, user.getName());

        // 生成token
        String authToken = jwtUtil.generate(user.getName());
        response.setHeader(jwtProperties.getHeader(), authToken);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("token", authToken);

        JSONObject serverInfo = loginUtil.generateServerInfo(user.getName());
        jsonObject.put("serverInfo", serverInfo);

        switch (op) {
            case ConstUtil.OP_FLOW_SHOW: {
                // 查看流程
                String strFlowId = StrUtil.getNullStr(map.get("flowId"));
                jsonObject.put("flowId", StrUtil.toInt(strFlowId, -1));
                break;
            }
            case ConstUtil.OP_FLOW_PROCESS: {
                // 处理流程
                String strMyActionId = StrUtil.getNullStr(map.get("myActionId"));
                long myActionId = StrUtil.toLong(strMyActionId);
                MyActionDb mad = new MyActionDb();
                mad = mad.getMyActionDb(myActionId);
                if (!mad.isLoaded()) {
                    return new Result<>(false, "动作不存在！");
                }

                if (!mad.getUserName().equals(userName)) {
                    return new Result<>(false, "动作与处理者不一致！");
                }
                jsonObject.put("myActionId", myActionId);
                break;
            }
            case ConstUtil.OP_MODULE: {
                String moduleCode = StrUtil.getNullStr(map.get("moduleCode"));
                jsonObject.put("moduleCode", moduleCode);
                break;
            }
            case ConstUtil.OP_MODULE_PAGE: {
                String moduleCode = StrUtil.getNullStr(map.get("moduleCode"));
                jsonObject.put("moduleCode", moduleCode);
                break;
            }
            case ConstUtil.OP_FLOW_PROCESS_LIST_PAGE:
                String type = StrUtil.getNullStr(map.get("type"));
                jsonObject.put("type", type);
                break;
            case ConstUtil.OP_FLOW_PROCESS_PAGE: {
                // 处理流程页面，可嵌入第三方系统
                String strMyActionId = StrUtil.getNullStr(map.get("myActionId"));
                long myActionId = StrUtil.toLong(strMyActionId);
                MyActionDb mad = new MyActionDb();
                mad = mad.getMyActionDb(myActionId);
                if (!mad.isLoaded()) {
                    return new Result<>(false, "动作不存在！");
                }
                if (!mad.getUserName().equals(userName)) {
                    return new Result<>(false, "动作与处理者不一致！");
                }
                jsonObject.put("myActionId", myActionId);
                break;
            }
            case ConstUtil.OP_FLOW_SHOW_PAGE: {
                // 查看流程
                String strFlowId = StrUtil.getNullStr(map.get("flowId"));
                jsonObject.put("flowId", StrUtil.toInt(strFlowId, -1));
                break;
            }
            case ConstUtil.OP_RESET_PWD:
                String email = map.get("email");
                if (!email.equals(user.getEmail())) {
                    return new Result<>(false, "用户或邮箱错误！");
                }
                break;
            case ConstUtil.OP_MODULE_EDIT: {
                String moduleCode = StrUtil.getNullStr(map.get("moduleCode"));
                String id = StrUtil.getNullStr(map.get("id"));
                jsonObject.put("moduleCode", moduleCode);
                jsonObject.put("id", id);

                ModuleSetupDb msd = new ModuleSetupDb();
                msd = msd.getModuleSetupDb(moduleCode);
                jsonObject.put("titleName", msd.getName());
                break;
            }
            case ConstUtil.OP_MODULE_SHOW: {
                String moduleCode = StrUtil.getNullStr(map.get("moduleCode"));
                String id = StrUtil.getNullStr(map.get("id"));
                jsonObject.put("moduleCode", moduleCode);
                jsonObject.put("id", id);
                jsonObject.put("visitKey", SecurityUtil.makeVisitKey(id));

                ModuleSetupDb msd = new ModuleSetupDb();
                msd = msd.getModuleSetupDb(moduleCode);
                jsonObject.put("titleName", msd.getName());
                break;
            }
        }

        return new Result<>(jsonObject);
    }

    @ApiOperation(value = "在ureport-community的查询表单中获取宏控件", notes = "在ureport-community的查询表单中获取宏控件", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "kind", value = "类型", required = false, dataType = "String"),
            @ApiImplicitParam(name = "formCode", value = "表单编码", required = true, dataType = "String"),
            @ApiImplicitParam(name = "fieldName", value = "字段名", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/getCtlHtmlForQuery", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String getCtlHtmlForQuery(@RequestParam(value = "kind", required = false) String kind, @RequestParam(value = "formCode", required = false) String formCode, @RequestParam(value = "fieldName") String fieldName) {
        return macroService.getCtlHtmlForQueryForEl(kind, formCode, fieldName);
    }

    @ApiOperation(value = "ureport-community中获取所有的表单", notes = "ureport-community中获取所有的表单", httpMethod = "POST")
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/listForm", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public String listForm() {
        FormDb fd = new FormDb();
        Vector<FormDb> formV = fd.list();
        com.alibaba.fastjson.JSONArray arr = new JSONArray();
        for (FormDb formDb : formV) {
            com.alibaba.fastjson.JSONObject json = new com.alibaba.fastjson.JSONObject();
            json.put("code", formDb.getCode());
            json.put("name", formDb.getName());
            arr.add(json);
        }
        return arr.toString();
    }

    @ApiOperation(value = "ureport-community中获取表单中的字段", notes = "ureport-community中获取表单中的字段", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "formCode", value = "表单编码", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/listField", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public Vector<FormField> listField(String formCode) {
        FormDb formDb = new FormDb();
        formDb = formDb.getFormDb(formCode);
        if (!formDb.isLoaded()) {
            return new Vector<>();
        }
        return formDb.getFields();
    }

    @ApiOperation(value = "扫码下载手机端的文件", notes = "扫码下载手机端的文件", httpMethod = "POST")
    @RequestMapping(value = "/mobileScanDownload", method = RequestMethod.GET, produces = {"text/html;charset=UTF-8;", "application/json;charset=UTF-8;"})
    public void mobileScanDownload(HttpServletResponse response) throws IOException {
        UserAgent ua = new UserAgent(request.getHeader("User-Agent"));
        OperatingSystem os = ua.getOperatingSystem();
        OperatingSystem os_parent = os.getGroup();
        boolean isMobile = os.isMobileDevice();
        if (isMobile) {
            boolean isAndroid = os_parent.equals(OperatingSystem.ANDROID);
            String downloadUrl = MobileScanDownload.downloadMobileClientByAngent(isAndroid);
            if (downloadUrl.endsWith(MobileScanDownload.IOS_NO_APPROVAL)) {
                response.getWriter().print("IOS提交审核中,请耐心等待!");
            } else {
                response.sendRedirect(downloadUrl);
            }
        }
    }

    @ApiOperation(value = "检查用户登录名", notes = "检查用户登录名")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userName", value = "用户名称", dataType = "String"),
            @ApiImplicitParam(name = "uId", value = "用户ID", dataType = "Integer"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/checkLoginName", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;"})
    public Result<Object> checkLoginName(@NotEmpty(message = "{user.name.notempty}") @Length(max = 20, message = "{user.name.length}") String userName, @RequestParam(defaultValue = "-1") Integer uId) {
        JSONObject json = new JSONObject();
        try {
            userService.chkLoginName(userName, uId);
            // 创建默认密码
            String mm = RandomSecquenceCreator.getId(8);
            json.put("result", 0);
            json.put("mm", mm);
        } catch (ValidateException e) {
            return new Result<>(false, e.getMessage());
        }
        return new Result<>(json);
    }

    @ApiOperation(value = "发送验证码，用于通过手机号登录", notes = "发送验证码，用于通过手机号登录", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @ResponseBody
    @RequestMapping(value = "/sendValidateCodeForMobileLogin", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;"})
    public Result<Object> sendValidateCodeForMobileLogin(@RequestParam String mobile) {
        if (!com.redmoon.oa.sms.Config.isValidMobile(mobile)) {
            return new Result<>(false, "手机号格式非法");
        }

        String sRand = authUtil.getValidateCode();
        RMCache.getInstance().putInGroup(mobile, "MOBILE_VALIDATE_CODE", sRand, 180);

        sRand = "短信验证码：" + sRand + "，3分钟内有效。请您尽快完成操作。如非本人操作，请忽略此短信。";
        if (SMSFactory.isUseSMS()) {
            IMsgUtil imu = SMSFactory.getMsgUtil();
            if (imu != null) {
                try {
                    imu.send(mobile, sRand, MessageDb.SENDER_SYSTEM);
                } catch (ErrMsgException e) {
                    return new Result<>(false, e.getMessage());
                }
            }
        } else {
            return new Result<>(false, "短信未启用");
        }
        return new Result<>();
    }

    @ApiOperation(value = "预览文件", notes = "预览文件", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "ID", required = true, dataType = "Long"),
            @ApiImplicitParam(name = "isFlow", value = "是否流程", required = true, dataType = "Boolean"),
            @ApiImplicitParam(name = "visitKey", value = "访问token", required = true, dataType = "String"),
    })
    @ApiResponses({ @ApiResponse(code = 200, message = "操作成功") })
    @RequestMapping("/preview")
    public void preview(HttpServletResponse response, @RequestParam Long id, @RequestParam Boolean isFlow, @RequestParam String visitKey) throws IOException, ErrMsgException {
        int r = com.redmoon.oa.security.SecurityUtil.validateVisitKey(visitKey, String.valueOf(id));
        if (r != 1) {
            response.getWriter().print(SecurityUtil.getValidateVisitKeyErrMsg(r));
            return;
        }
        IAttachment att;
        if (isFlow) {
            att = new Attachment(id);
        } else {
            att = new com.redmoon.oa.visual.Attachment(id);
        }
        if (att.isLoaded()) {
            fileService.preview(response, att.getVisualPath() + "/" + att.getDiskName(), false);
        } else {
            LogUtil.getLog(getClass()).error("Attachment id: " + id + " isFLow: " + isFlow + " is not found");
            response.getWriter().print("Attachment id: " + id + " isFLow: " + isFlow + " is not found");
        }
    }

    @ApiOperation(value = "更新表单中的记录", notes = "更新表单中的记录（添加、修改、删除），用于第三方系统对接本系统", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "jsonObject", value = "更新内容", required = true, dataType = "JSONObject"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @ResponseBody
    @RequestMapping(value = "/updateForm", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;"})
    public Result<Object> updateForm(@RequestBody com.alibaba.fastjson.JSONObject jsonObject) {
        boolean re = false;
        String formCode = jsonObject.getString("formCode");
        String op = jsonObject.getString("op");
        JSONArray fields = jsonObject.getJSONArray("fields");
        try {
            FormDb fd = new FormDb();
            fd = fd.getFormDb(formCode);

            if ("create".equals(op)) {
                String cwsId = "", creator = "", unitCode = "", parentFormCode = "";
                if (jsonObject.containsKey("cwsId")) {
                    cwsId = jsonObject.getString("cwsId");
                }
                if (jsonObject.containsKey("creator")) {
                    creator = jsonObject.getString("creator");
                }
                if (jsonObject.containsKey("unitCode")) {
                    unitCode = jsonObject.getString("unitCode");
                }
                if (jsonObject.containsKey("parentFormCode")) {
                    parentFormCode = jsonObject.getString("parentFormCode");
                }
                com.redmoon.oa.visual.FormDAO fdao = new com.redmoon.oa.visual.FormDAO(fd);
                for (Object o : fields) {
                    com.alibaba.fastjson.JSONObject json = (com.alibaba.fastjson.JSONObject) o;
                    String name = json.getString("name");
                    String value = json.getString("value");
                    fdao.setFieldValue(name, value);
                }
                fdao.setFlowTypeCode(String.valueOf(System.currentTimeMillis()));
                fdao.setCwsId(StrUtil.emptyTo(cwsId, com.redmoon.oa.visual.FormDAO.TEMP_CWS_ID)); // 关联的模块的ID
                fdao.setCreator(StrUtil.emptyTo(creator, ConstUtil.USER_SYSTEM)); // 参数为用户名（创建记录者），必填
                fdao.setUnitCode(StrUtil.emptyTo(unitCode, ConstUtil.DEPT_ROOT)); // 置单位编码，必填
                fdao.setCwsParentForm(parentFormCode); // 如为嵌套表，则置主表单的编码，且必填，否则选填
                re = fdao.create();
            } else if ("edit".equals(op)) {
                long id = -1;
                if (!jsonObject.containsKey("id")) {
                    return new Result<>(false, "id为空");
                }
                com.redmoon.oa.visual.FormDAO fdao = new com.redmoon.oa.visual.FormDAO();
                fdao = fdao.getFormDAOByCache(id, fd);
                if (!fdao.isLoaded()) {
                    return new Result<>(false, "记录不存在");
                }
                for (Object o : fields) {
                    com.alibaba.fastjson.JSONObject json = (com.alibaba.fastjson.JSONObject) o;
                    String name = json.getString("name");
                    String value = json.getString("value");
                    fdao.setFieldValue(name, value);
                }
                re = fdao.save();
            } else if ("del".equals(op)) {
                long id = -1;
                if (!jsonObject.containsKey("id")) {
                    return new Result<>(false, "id为空");
                }
                com.redmoon.oa.visual.FormDAO fdao = new com.redmoon.oa.visual.FormDAO();
                fdao = fdao.getFormDAOByCache(id, fd);
                if (!fdao.isLoaded()) {
                    return new Result<>(false, "记录不存在");
                }
                re = fdao.del();
            }

            if (re) {
                FormCache fc = new FormCache(fd);
                fd.getPrimaryKey().setValue(formCode);
                fc.refreshSave(fd.getPrimaryKey());
            }
        } catch (ErrMsgException | SQLException e) {
            LogUtil.getLog(getClass()).error(e);
            return new Result<>(false, e.getMessage());
        }
        return new Result<>(re);
    }

    @ApiOperation(value = "测试连接器", notes = "测试连接器", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "jsonObject", value = "更新内容", required = true, dataType = "JSONObject"),
    })
    @ApiResponses({@ApiResponse(code = 200, message = "操作成功")})
    @ResponseBody
    @RequestMapping(value = "/testConnector", method = RequestMethod.POST, produces = {"text/html;charset=UTF-8;", "application/json;"})
    public Result<Object> test(@RequestBody com.alibaba.fastjson.JSONObject jsonObject) {
        JSONObject json = new JSONObject();
        json.put("field", jsonObject.getString("field"));
        json.put("result", "1");
        return new Result<>(json);
    }
}
